module xpip_rtl_dcu(
  input logic clk, rst_n,
  xpip_intf.dcu inf
);
  `XPIP_DEF_PARAM
      
  logic tWr;
  idx_t tRadr[2], tWadr;
  logic[NUM_DCHE_ASO-1:0] tBe;
  tag_t[NUM_DCHE_ASO-1:0] tDatai, tDatao[2];
  
  logic dWr[NUM_SMEM_BK];
  smadr_t[NUM_SMEM_BK-1:0] dRadr, dWadr;
  logic[NUM_SMEM_BK-1:0][WORD_BYTES-1:0] dBe;
  byt[NUM_SMEM_BK-1:0][WORD_BYTES-1:0] dDatai, dDatao;

  logic sWr;
  dcsdb_t[NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0] sRadr;
  dcsdb_t sWadr;
  word[NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0] sDatai, sDatao;
  
  logic[NUM_SMEM_BK-1:0] rWr;
  logic[NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0] rBe;
  dcrdb_t[NUM_SMEM_BK-1:0] rWadr;
  dcrdb_t rRadr;
  byt[NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0][WORD_BYTES-1:0] rDatao;
  byt[NUM_SMEM_BK-1:0][WORD_BYTES-1:0] rDatai;

  dcu_inf_s s, sn;
  dcu_io_inf_s io, ion;
  dcu_o_inf_s o, on;
  dcu_r_inf_s r, rn;
  dcu_e_inf_s e, en;
  dcu_c_inf_s c, cn;
        
  always_ff@(posedge clk or negedge rst_n)
    if(!rst_n) begin
      o <= dcu_o_inf_def;
      r <= dcu_r_inf_def;
      e <= dcu_e_inf_def;
      c <= dcu_c_inf_def;
      s <= dcu_inf_def;
      io <= dcu_io_inf_def;
    end else begin
      o <= on;
      r <= rn;
      e <= en;
      c <= cn;
      s <= sn;
      io <= ion;
    end
    
  always_comb
  begin : comb_logic
    begin : init
      sn = s;
      on = o;
      rn = r;
      en = e;
      cn = c;
      inf.dcu2tlb = dcu2tlb_def;
      dWr = '{default : '0};
      sWr = '0;
      sWadr = '0;
    end : init
    
    begin : lsu_req
      dcsdb_t sid;
      for(int i = 0; i < NUM_DCU_SDB; i++)
        if(on.sdbv[i]) begin
          sid = i;
          break;
        end
      
      if(io.lsu.req.sd && io.dcu2lsu.rsp.sd) begin
        rn.dib[rn.dibwp].d = io.lsu.sd;
        rn.dib[rn.dibwp].sid = sid;
        sWr = '1;
        sWadr = rn.dibwp;
        rn.dibwp++;
      end
      
      if(io.lsu.req.a && io.dcu2lsu.rsp.a) begin
        if(io.lsu.ar.ls) begin
          rn.dib[rn.dibrdy].ar = io.lsu.ar;
          rn.dibrdy++;
        end else begin
          rn.rib[rn.ribwp].ar = io.lsu.ar;
          rn.ribwp++;
        end
      end
      rn.dibf = rn.dibrp == rn.dibwp && (r.dibrp == (r.dibwp + 1'b1) || r.dibf);
      rn.dibrf = rn.dibrp == rn.dibrdy && (r.dibrp == (r.dibrdy + 1'b1) || r.dibrf);
      rn.ribf = rn.ribrp == rn.ribwp && (r.ribrp == (r.ribwp + 1'b1) || r.ribf);
    end : lsu_req
    
    begin : tag_read_update
      if(c.irRd) begin
        cn.irSt = cn.cstate[c.irRdIdx];
        cn.irCnt = cn.cnt[c.irRdIdx];
        cn.irLck = cn.lck[c.irRdIdx];
        cn.irRd = '0;
      end
      if(c.erWr && cn.irRdIdx == c.erWrIdx) begin
        cn.irSt[c.erWrAso] = c.erWrSt;
        cn.irCnt = c.erWrCnt;
        if(c.erLckWr)
          cn.irLck[c.erWrAso] = c.erWrLck;
      end
      if(c.irWr && cn.irRdIdx == c.irWrIdx) begin
        cn.irSt[c.irWrAso] = c.irWrSt;
        cn.irCnt = c.irWrCnt;
        if(c.irLckWr)
          cn.irLck[c.irWrAso] = c.irWrLck;
      end
              
      if(c.erRd) begin
        cn.erSt = cn.cstate[c.erRdIdx];
        cn.erCnt = cn.cnt[c.erRdIdx];
        cn.erLck = cn.lck[c.erRdIdx];
        cn.erRd = '0;
      end
      if(c.erWr && cn.erRdIdx == c.erWrIdx) begin
        cn.erSt[c.erWrAso] = c.erWrSt;
        cn.erCnt = c.erWrCnt;
        if(c.erLckWr)
          cn.erLck[c.erWrAso] = c.erWrLck;
      end
      if(c.irWr && cn.erRdIdx == c.irWrIdx) begin
        cn.erSt[c.irWrAso] = c.irWrSt;
        cn.erCnt = c.irWrCnt;
        if(c.erLckWr)
          cn.erLck[c.irWrAso] = c.irWrLck;
      end
      
      if(c.irWr) begin
        cn.irWr = '0;
        cn.cstate[c.irWrIdx][c.irWrAso] = c.irWrSt;
        cn.cnt[c.irWrIdx] = c.irWrCnt;
        if(c.irLckWr)
          cn.lck[c.irWrIdx][c.irWrAso] = c.irWrLck;
      end else if(c.erWr) begin
        cn.erWr = '0;
        cn.cstate[c.erWrIdx][c.erWrAso] = c.erWrSt;
        cn.cnt[c.erWrIdx] = c.erWrCnt;
        if(c.erLckWr)
          cn.lck[c.erWrIdx][c.erWrAso] = c.erWrLck;
      end
    end : tag_read_update

    begin : biu_rsp
      if(io.biu.req.ia && io.dcu2biu.rsp.ia) begin
        if(io.biu.ia.hasData) begin
          en.edib[en.edibrdy].a = io.biu.ia;
          if(io.biu.ia.at inside {at_rd, at_wr}) begin
            en.edib[en.edibrdy].a.adr = e.erb[io.biu.ia.id].oa.adr;
          end
          en.edibrdy++;
        end begin
          en.erib[en.eribwp].a = io.biu.ia;
          if(io.biu.ia.at inside {at_rd, at_wr}) begin
            en.erib[en.edibrdy].a.adr = e.erb[io.biu.ia.id].oa.adr;
          end
          en.eribwp++;
        end
      end
      
      if(io.biu.req.id && io.dcu2biu.rsp.id) begin
        en.edib[en.edibrdy].a = io.biu.ia;
        en.edib[en.edibrdy].d[io.biu.req.idcl] = io.biu.id;
      end
      
      en.eribf = en.eribrp == en.eribwp && (e.eribrp == (e.eribwp + 1'b1) || e.eribf);
      en.edibf = en.edibrp == en.edibwp && (e.edibrp == (e.edibwp + 1'b1) || e.edibf);
      en.edibrf = en.edibprc == en.edibrdy && (e.edibprc == (e.edibrdy + 1'b1) || e.edibrf);
    end : biu_rsp
            
    begin : tlb_proc_part0
      rn.tlbprdy = '0;
      if(io.dcu2tlb.req && r.tlbp.v) begin
        rn.tlbp.tlb = io.tlb.i;
        if(io.tlb.i.wp && !r.tlbp.ar.ls)
          rn.tlbp.code = exr_err;
        else if(io.tlb.i.prot > r.tlbp.ar.prot) 
          rn.tlbp.code = exr_prot;
        else if(io.tlb.i.miss)
          rn.tlbp.code = exr_tlb;
        else
          rn.tlbp.code = exr_ok;
        rn.tlbp.padr = r.tlbp.ar.chadr;
        rn.tlbp.padr[WID_PADR - 1:WID_NVADR] = io.tlb.i.pfn;
        rn.tlbp.ahash = hashgen(rn.tlbp.padr.t, rn.tlbp.padr.idx);
        
        if(rn.tlbp.code inside {exr_err, exr_tlb}) begin
          if(!sn.tlbpWr) begin
            rn.tlbp.v = '0;
            sn.tlbpWr = '1;
            sn.tlbpRrb.ls = rn.tlbp.ar.ls;
            sn.tlbpRrb.s.id = rn.tlbp.ar.rid;
            sn.tlbpRrb.s.exp = '{default : rn.tlbp.code};
          end
        end else
          rn.tlbprdy = '1;
      end else
        rn.tlbprdy = r.tlbp.v;
    end : tlb_proc_part0
    
    begin : internal_req_proc
      ///check_rwbrdy
      rn.rwbrdy = '0;
      for(int i = 0; i < NUM_DCU_RWB; i++)
        if(rn.rwbv[i]) begin
          if(rn.rwb[i].efw)
            rn.rwbrdy[i] = en.erbv != '1;
          else
            rn.rwbrdy[i] = !rn.rwb[i].cew;
        end

      ///stage 2 assign to orb or erb
      if(r.irp[1].v) begin
        logic fnd, ex, oc, wr, ls, wrc;
        cache_state_t st;
        cache_require_e cr;
        ccnt_t[NUM_DCHE_ASO - 1:0] cnt;
        lck_t lck;
        
        cr = cr_unique;
        st = cs_i;
        {fnd, ex, oc, wr, ls, wrc} = '0;
        rn.irp[2] = r.irp[1];
        cnt = cn.irCnt;
        for(int i = 0; i < NUM_DCHE_ASO; i++) begin
          if(cn.irSt[i] != cs_i && (io.irTag[i].par ^ rn.irp[2].padr.t.par & inf.cfg.ocm) == '0
             && io.irTag[i].tag == rn.irp[2].padr.t.tag) begin
            rn.irp[2].hit = '1;
            rn.irp[2].aso = i;
            rn.irp[2].cs = cn.irSt[i];
          end
        end
        lck = cn.irLck[rn.irp[2].aso];
        
        if(rn.irp[2].tlb.mt == mt_sm || rn.irp[2].ar.sm) begin
          oc = '1;
        end else if(!rn.irp[2].hit) begin
          ls = rn.irp[2].ar.ls;
          ex = '1;
          cr = rn.irp[2].ar.ls ? cr_shared : cr_unique;
        end else begin
          if(!rn.irp[2].ar.lg) begin
            oc = '1;
            if(!rn.irp[2].ar.ls) begin
              wr = '1;
              st = cs_ud;
            end
          end else if(rn.irp[2].cs inside {cs_uc, cs_ud}) begin
            oc = '1;
            if(!rn.irp[2].ar.ls) begin
              wr = '1;
              st = cs_ud;
            end
          end else if(rn.irp[2].ar.ls)
            oc = '1;
          else begin
            cr = cr_unique;
            ex = '1;
            ls = '1;
          end
        end
        
        if(ex) begin
          dcrwb_t rwbid;
          for(int i = 0; i < NUM_DCU_RWB; i++)
            if(rn.rwbv[i])
              rwbid = i;
          
          for(int i = 0; i < NUM_DCU_ERB; i++) begin
            if(en.erbv[i] && rn.irp[2].ahash == en.erb[i].ahash) begin
              rn.irp[2].cid = i;
              wrc |= ls == (en.erb[i].oa.at == at_wr);
            end
          end
          
          if(wrc || en.erbv == '1) begin
            if(rn.rwbv != '1) begin
              rn.irp[1].v = '0;
              rn.rwbv[rwbid] = '1;
              rn.rwb[rwbid].cew = wrc;
              rn.rwb[rwbid].efw = en.erbv == '1;
              rn.rwb[rwbid].cid = rn.irp[2].cid;
              rn.rwb[rwbid].ar = rn.irp[2].ar;
              rn.rwb[rwbid].tlb = rn.irp[2].tlb;
              rn.rwb[rwbid].d = rn.irp[2].d;
              rn.rwb[rwbid].sid = rn.irp[2].sid;
              rn.rwb[rwbid].padr = rn.irp[2].padr;
              rn.rwb[rwbid].ahash = rn.irp[2].ahash;
            end
          end if(!en.irWr) begin
            rn.irp[1].v = '0;
            rn.irp[2].ex = '1;
            rn.irp[2].cs = st;
            rn.irp[2].cr = cr;
            rn.irp[2].ls = ls;
            en.irWr = '1;
            en.irErb.oa.adr = rn.irp[2].padr;
            en.irErb.oa.cs = rn.irp[2].cs;
            en.irErb.oa.cr = rn.irp[2].cr;
            en.irErb.oa.at = ls ? at_rd : at_wr;
            en.irErb.ahash = rn.irp[2].ahash;
            en.irErb.sid = rn.irp[2].sid;
            en.irErb.ar = rn.irp[2].ar;
            en.irErb.tlb = rn.irp[2].tlb;
            en.irErb.d = rn.irp[2].d;
            en.irErb.sid = rn.irp[2].sid;
          end
        end else if(oc) begin
          logic lckpass;
          lckpass = '1;
          rn.irp[2].oc = '1;
          case(rn.irp[2].ar.ch)
            ch_cs   : cnt[rn.irp[2].aso] = '0;
            ch_lck  : cnt[rn.irp[2].aso] = ct_lck;
            ch_nor  : cnt[rn.irp[2].aso] = ct_nor;
            default : cnt[rn.irp[2].aso] = ct_nor;
          endcase
          if(rn.irp[2].ar.llsc) begin
            if(!rn.irp[2].ar.ls) begin
              lckpass = lck.id[rn.irp[2].ar.tid];
              if(lckpass)
                lck = '0;
            end
            lck.id[rn.irp[2].ar.tid] = '1;
          end
          if((!on.irWr || !wr) && lckpass) begin
            if(wr) begin
              cn.irWr = '1;
              cn.irLckWr = rn.irp[2].ar.llsc;
              cn.irWrCnt = cnt;
              cn.irWrLck = lck;
              cn.irWrSt = st;
              cn.irWrIdx.idx = rn.irp[2].padr.idx;
              cn.irWrIdx.par = rn.irp[2].padr.t.par | ~inf.cfg.ocm;
              cn.irWrAso = rn.irp[2].aso;
            end
            
            rn.irp[1].v = '0;
            on.irOrb.adr.idx = rn.irp[2].padr.idx;
            on.irOrb.adr.par = rn.irp[2].padr.t.par;
            on.irOrb.adr.aso = rn.irp[2].aso;
            on.irOrb.sm = rn.irp[2].tlb.mt == mt_sm;
            on.irOrb.ar = rn.irp[2].ar;
            on.irOrb.sid = rn.irp[2].sid;
          end
          
          if(!lckpass && !sn.irpWr) begin
            rn.irp[1].v = '0;
            sn.irpWr = '1;
            sn.irpRrb.s.id = rn.irp[2].ar.rid;
            sn.irpRrb.s.exp = '{default : exr_exok};
            sn.irpRrb.ls = rn.irp[2].ar.ls;
            sn.irpRrb.rid = '0;
          end
        end
        rn.irp[2].v = !rn.irp[1].v;
      end
      
      ///stage 1, tag memory access
      if(!rn.irp[1].v) begin
        if(!c.irRd || !cn.irRd) begin
          rn.irp[1] = r.irp[0];
          rn.irp[0].v = '0;
        end
      end
      
      ///stage 0, select
      if(!rn.irp[0].v) begin
        ///select from rwb first
        if(rn.rwbrdy != '0) begin
          dcrwb_t rwbid;
          for(int i = 0; i < NUM_DCU_RWB; i++)
            if(rn.rwbrdy[i])
              rwbid = i;
          rn.irp[0].ar = rn.rwb[rwbid].ar;
          rn.irp[0].tlb = rn.rwb[rwbid].tlb;
          rn.irp[0].d = rn.rwb[rwbid].d;
          rn.irp[0].sid = rn.rwb[rwbid].sid;
          rn.irp[0].padr = rn.rwb[rwbid].padr;
          rn.irp[0].ahash = rn.rwb[rwbid].ahash;
        end else if(rn.tlbprdy) begin
          rn.irp[0] = r.tlbp;
          rn.tlbp.v = '0;
        end
        cn.irRd = !rn.irp[0].ar.sm && rn.irp[0].v;
        cn.irRdIdx.idx = rn.irp[0].padr.idx;
        cn.irRdIdx.par = rn.irp[0].padr.t.par | ~inf.cfg.ocm;
      end
    end : internal_req_proc
    
    begin : external_req_proc
      ///stage 3, finish
      if(e.erp[2].v) begin
        if(e.erp[2].iaWait || !io.dcu2biu.req.ir || io.biu.rsp.ir)
          en.erp[2].v = '0;
      end
            
      ///stage 2,  tag check
      if(e.erp[1].v && !en.erp[2].v) begin
        logic wr, hit, full, lckpass;
        dcewb_t ewbid;
        dcrdb_t rid;
        dcerb_t eid;
        cache_state_t st;
        aso_t aso;
        ccnt_t[NUM_DCHE_ASO - 1:0] cnt;
        lck_t lck;
        en.erp[1].v = '0;
        {ewbid, hit, wr, aso, rid, full, lckpass} = {'0, 2'b11};
        st = cs_i;
        cnt = cn.erCnt;
        en.erp[2] = e.erp[1];
        en.erp[2].start = '1;
        en.erp[2].adr = en.erp[2].ia.adr;
        eid = en.erp[2].ia.id;
        for(int i = 0; i < NUM_DCHE_ASO; i++) begin
          if(cn.erSt[i] == cs_i)
            full = '0;
          if(cn.erSt[i] != cs_i && (io.erTag[i].par ^ en.erp[2].ia.adr.t.par & inf.cfg.ocm) == '0
             && io.erTag[i].tag == en.erp[2].ia.adr.t.tag) begin
            hit = '1;
            aso = i;
            en.erp[2].cs = cn.erSt[i];
          end
        end

        st = en.erp[2].ia.cs;
        lck = cn.erLck[aso];
        if(en.erp[2].ia.at == at_sm) begin
          en.erp[2].adr.par = en.erp[2].ia.adr.t.par & inf.cfg.ocm;
          en.erp[2].cfill = en.erp[2].ia.hasData;
        end if(hit) begin
          en.erp[2].adr.par = en.erp[2].ia.adr.t.par | ~inf.cfg.ocm;
          en.erp[2].adr.aso = aso;
          en.erp[2].cfill = en.erp[2].ia.hasData;
          if(en.erp[2].ia.at == at_snp) begin
            case(en.erp[2].ia.cr)
              cr_inv    : if(en.erp[2].cs inside {cs_ud, cs_sd}) begin
                            en.erp[2].cwb = '1;
                            en.erp[2].ir.hasData = '1;
                            st = cs_i;
                            wr = '1;
                          end
              cr_shared : if(en.erp[2].cs == cs_uc) begin
                            st = cs_sc;
                            wr = '1;
                          end else if(en.erp[2].cs == cs_ud) begin
                            st = cs_sd;
                            wr = '1;
                            en.erp[2].ir.hasData = '1;
                            en.erp[2].cwb = '1;
                          end
              cr_clean  : if(en.erp[2].cs == cs_ud) begin
                            en.erp[2].cwb = '1;
                            en.erp[2].ir.hasData = '1;
                            st = cs_uc;
                            wr = '1;
                          end else if(en.erp[2].cs == cs_sd) begin
                            en.erp[2].cwb = '1;
                            en.erp[2].ir.hasData = '1;
                            st = cs_sc;
                            wr = '1;
                          end
              cr_nshared: if(en.erp[2].cs == cs_sd) begin
                            en.erp[2].cwb = '1;
                            en.erp[2].ir.hasData = '1;
                            st = cs_uc;
                            wr = '1;
                          end else if(en.erp[2].cs == cs_sc) begin
                            st = cs_uc;
                            wr = '1;
                          end
               cr_unique: if(en.erp[2].cs == cs_sd) begin
                            st = cs_ud;
                            wr = '1;
                          end else if(en.erp[2].cs == cs_sc) begin
                            st = cs_uc;
                            wr = '1;
                          end
            endcase
          end else if(en.erp[2].ia.at inside {at_rd, at_wr}) begin
            wr = st != en.erp[2].cs;
          end
        end else if(en.erp[2].ia.at inside {at_rd, at_wr}) begin
          ///need fill a cache line?
          en.erp[2].cfill = en.erp[2].ia.hasData
            && ((en.erp[2].tlb.mt inside {mt_wtra, mt_wtrwa, mt_wbra, mt_wbrwa} && en.erp[2].ar.ls)
            || (en.erp[2].tlb.mt inside {mt_wtrwa, mt_wbrwa} && !en.erp[2].ar.ls));
          en.erp[2].cfill &= en.erp[2].ar.ch != ch_na;
          en.erp[2].cwb = en.erp[2].cfill && full;
          wr = en.erp[2].cfill;
        end else if(en.erp[2].ia.at == at_snp) begin
        end
        
        en.erp[2].rdbw = en.erp[2].ia.at == at_rd && en.erp[2].ia.hasData && en.erp[2].ar.ls;
                
        if(!en.erp[2].ia.resp inside {rt_slverr, rt_err}) begin ///response is error
          wr = '0;
          en.erp[2].rdbw = '0;
          en.erp[2].cfill = '0;
          en.erp[2].cwb = '0;
        end
        
        ///snoop must wait for write out for same adr
        if(en.erp[2].ia.at == at_snp) begin
          logic fnd;
          {fnd} = '0;
          for(int i = 0; i < NUM_DCU_ERB; i++)
            if(en.erbv[i] && en.erb[i].ahash == en.erp[2].ahash && en.erb[i].oa.at == at_wr) begin
              en.erp[2].cid = i;
              en.erp[2].iaWait = '1;
            end
          for(int i = 0; i < NUM_DCU_EWB; i++)
            if(!en.ewb[i].v) begin
              fnd = '1;
              ewbid = i;
            end
          en.erp[2].start &= !en.erp[2].iaWait || fnd;
        end
        
        ///find write aso
        if(en.erp[2].cwb) begin
          ccnt_t cnt2;
          logic fnd;
          fnd = '0;
          
          for(int i = 0; i < NUM_DCHE_ASO; i++) begin
            if(cnt2 > cn.erCnt[i]) begin
              fnd = '1;
              cnt2 = cn.erCnt[i];
              en.erp[2].asoWr = i;
            end
          end
          en.erp[2].flushPadr.idx = en.erp[2].padr.idx;
          en.erp[2].flushPadr.t = io.erTag[en.erp[2].asoWr];
          en.erp[2].csf = cn.erSt[en.erp[2].asoWr];
          en.erp[2].start &= !on.erWr;
        end else if(en.erp[2].cfill) begin
          logic fnd;
          fnd = '0;
          if(hit)
            en.erp[2].asoWr = aso;
          else
            for(int i = 0; i < NUM_DCHE_ASO; i++)
              if(cn.erSt[i] == cs_i) begin
                en.erp[2].asoWr = i;
                fnd = '1;
              end
              
            if(!fnd) begin
              for(int i = 0; i < NUM_DCHE_ASO; i++)
                if(cn.erSt[i] inside {cs_uc, cs_sc}) begin
                  en.erp[2].asoWr = i;
                  en.erp[2].evict = '1;
                end              
            end
            en.erp[2].csf = cn.erSt[en.erp[2].asoWr];
            en.erp[2].flushPadr.idx = en.erp[2].padr.idx;
            en.erp[2].flushPadr.t = io.erTag[en.erp[2].asoWr];
            en.erp[2].start &= !on.erWr;
        end
        
        if(en.erp[2].rdbw)
          en.erp[2].start &= !on.erWr;
        
        if(en.erp[2].ar.ls || en.erb[eid].oa.at == at_wr)
          en.erp[2].start &= sn.erpWr;
        
        en.erp[2].start &= !wr || !cn.erWr;

        if(en.erp[2].evict)
          for(int i = 0; i < NUM_DCHE_ASO; i++)
            if(cnt[i] != '0)
              cnt[i]--;
        if(en.erp[2].ia.at inside {at_rd, at_wr})
          case(en.erp[2].ar.ch)
            ch_cs   : cnt[en.erp[2].asoWr] = '0;
            ch_lck  : cnt[en.erp[2].asoWr] = ct_lck;
            ch_nor  : cnt[en.erp[2].asoWr] = ct_nor;
            default : cnt[en.erp[2].asoWr] = ct_nor;
          endcase
        else
          cnt[en.erp[2].asoWr] = ct_nor;
          
        if(en.erp[2].ia.lck) begin
          if(en.erp[2].ia.at inside {at_rd, at_wr}) begin
            if(!en.erp[2].ar.ls && en.erp[2].ia.at == at_rd) begin
              lckpass = lck.id[en.erp[2].ar.tid] && en.erp[2].ia.resp == rt_exok;
              if(lckpass)
                lck.id = '0;
              lck.id[en.erp[2].ar.tid] = '1;
            end else
              lck.id[en.erp[2].ar.tid] = '1;
          end else if(en.erp[2].ia.at == at_snp) begin
            if(en.erp[2].ia.hasData) begin
              lckpass = lck.ex;
              if(lckpass)
                lck = '0;
            end
            lck.ex = '1;
          end
        end
        
        if(!lckpass) begin
          if(!sn.erpWr && en.erp[2].ia.at inside {at_rd, at_wr}) begin
            sn.erpWr = '1;
            sn.erpRrb.s.id = en.erb[eid].ar.rid;
            sn.erpRrb.s.exp = '{default : exr_ok};
            sn.erpRrb.ls = en.erb[eid].ar.ls;
          end
          en.erp[2].ir.cs = en.erp[2].cs;
          en.erp[2].ir.ns = st;
          en.erp[2].ir.id = eid;
          en.erp[2].ir.at = en.erp[2].ia.at;
          en.erp[2].ir.resp = rt_ok;
        end if(en.erp[2].start) begin
          cn.erWrCnt = cnt;
          cn.erWrLck = lck;
          cn.erLckWr = en.erp[2].ia.lck;
          if(en.erp[2].rdbw || en.erp[2].cfill) begin
            on.erWr = '1;
            on.erOrb.adr = en.erp[2].adr;
            on.erOrb.ar = en.erp[2].ar;
            on.erOrb.clcwr = en.erp[2].cfill;
            on.erOrb.clrwr = en.erp[2].rdbw;
            on.erOrb.sid = en.erp[2].edib;
          end
          
          if(en.erp[2].cwb) begin
            on.erWr = '1;
            on.erOrb.cr = '1;
            on.erOrb.adr = en.erp[2].adr;
          end
          
          if(en.erp[2].iaWait) begin
            en.ewb[ewbid].v = '1;
            en.ewb[ewbid].reCheck = '1;
            en.ewb[ewbid].cid = en.erp[2].cid;
            en.ewb[ewbid].ia = en.erp[2].ia;
          end
          
          ///erb retire, rrb alloc
          if(en.erp[2].ia.at inside {at_rd, at_wr}) begin
            if(en.erp[2].cwb) begin
              en.erb[eid].oa.at = at_wr;
              en.erb[eid].oa.adr = en.erp[2].flushPadr;
              en.erb[eid].flush = '1;
              en.erb[eid].areq = '1;
              en.erb[eid].ahash = hashgen(en.erp[2].flushPadr.t, en.erp[2].flushPadr.idx);
            end

            if(!en.erp[2].ar.ls && en.erb[eid].oa.at != at_wr) begin
              ///a read before write, not rdy for rrb
              en.erbv[eid] = '0;
            end else if(!en.erb[eid].flush) begin ///flush has no erb
              lsu_exrsp_e exp;
              case(en.erp[2].ia.resp)
                rt_slverr,
                rt_err    : exp = exr_err;
                rt_ok     : exp = exr_ok;
                rt_exok   : exp = exr_exok;
              endcase
              en.erbv[eid] = '0;
              ///alloc rrb
              sn.erpWr = '1;
              sn.erpRrb.s.id = en.erb[eid].ar.rid;
              sn.erpRrb.s.exp = '{default : exp};
              sn.erpRrb.ls = en.erb[eid].ar.ls;
              sn.erpRrb.rid = en.erp[2].rid;
            end
            for(int i = 0; i < NUM_DCU_RWB; i++)
              if(rn.rwbv[i] && rn.rwb[i].cew && rn.rwb[i].cid == eid)
                rn.rwb[i].cew = '0;
            for(int i = 0; i < NUM_DCU_EWB; i++)
              if(en.ewb[i].v && en.ewb[i].cid == eid)
                en.ewb[i].reCheck = '1;
          end
          
          if(en.erp[2].cfill)
            cn.erWrTag = en.erp[2].padr.t;
          cn.erWr = wr;
          cn.erWrAso = en.erp[2].asoWr;
          cn.erWrSt = st;
          if(cn.erWr) begin
            if(en.erp[2].cwb)
              for(int i = 0; i < NUM_DCHE_ASO; i++)
                if(cn.erWrCnt[i] != '0)
                  cn.erWrCnt[i]--;
            cn.erWrCnt[en.erp[2].adr.aso] = '1;
          end
          en.erp[2].ir.cs = en.erp[2].cs;
          en.erp[2].ir.ns = st;
          en.erp[2].ir.id = eid;
          en.erp[2].ir.at = en.erp[2].ia.at;
          en.erp[2].ir.resp = rt_ok;
        end else
          en.erp[2].v = '0; ///!en.erp[1].v
      end
      
      ///stage 1, tag check
      if(!en.erp[1].v) begin
        if(!c.erRd || !cn.erRd) begin
          en.erp[1] = e.erp[0];
          en.erp[0].v = '0;
        end
      end
            
      ///stage 0, select a ext req to process
      if(!en.erp[0].v) begin
        logic fnd;
        dcewb_t ewbid;
        fnd = '0;
        
        en.erp[0] = dcu_erp_inf_def;
        for(int i = 0; i < NUM_DCU_EWB; i++)
          if(en.ewb[i].v && en.ewb[i].reCheck)
            begin
              fnd = '1;
              ewbid = i;
            end
            
        if(fnd) begin
          en.ewb[ewbid].v = '0;
          en.ewb[ewbid].reCheck = '0;
          en.erp[0].ia = en.ewb[ewbid].ia;
          en.erp[0].v = '1;
        end if(en.edibprc != en.edibwp || en.edibf) begin
          en.erp[0].v = '1;
          en.erp[0].edib = en.edibprc;
          en.erp[0].ia = en.edib[en.edibprc].a;
          en.edibprc++;
        end else if(en.eribrp != en.eribwp || en.eribf) begin
          en.erp[0].v = '1;
          en.erp[0].ia = en.erib[en.eribrp].a;
          en.eribrp++;
        end
        en.erp[0].ar = e.erb[en.erp[0].ia.id].ar;
        en.erp[0].tlb = e.erb[en.erp[0].ia.id].tlb;
        en.erp[0].padr = en.erp[0].ia.at inside {at_rd, at_wr} ? e.erb[en.erp[0].ia.id].oa.adr : en.erp[0].ia.adr;
        en.erp[0].ahash = hashgen(en.erp[0].padr.t, en.erp[0].padr.idx);
        cn.erRdIdx.idx = en.erp[0].ia.adr.idx;
        cn.erRdIdx.par = en.erp[0].ia.adr.t.par | ~inf.cfg.ocm;
        cn.erRd = en.erp[0].v && en.erp[0].ia.at != at_sm;
      end
    end : external_req_proc
    
    begin : onchip_access_proc
      logic fnd;
      dcasb_t asid;
      dcorb_t oid;
      dcrdb_t rid;
      {fnd, oid, asid, rid} = '0;
      
      ///stage 0 select a request for om access      
      for(int i = 0; i < NUM_DCU_ASB; i++)
        if(!on.asbv[i]) begin
          asid = i;
          on.rstrb[i] = '0;
          break;
        end
        
      for(int i = 0; i < NUM_DCU_RDB; i++)
        if(!on.rdbv[i]) begin
          rid = i;
          break;
        end
            
      for(int i = 0; i < NUM_DCU_ORB; i++)
        if(on.orb[i].st == dos_rdy) begin
          if((on.orb[i].cr && !on.crp[2].v)
            || (on.orb[i].clrwr && on.rdbv != '1)
            || (on.orb[i].rw && on.rdbv != '1)
            ) begin
            fnd = '1;
            oid = i;
            break;
          end
        end
                
      ///select a orb to asb
      if(fnd)begin
        if(on.orb[oid].clrwr
          || on.orb[oid].clcwr
          || on.orb[oid].cr
        ) begin
          if(on.orb[oid].cr) begin
            on.crp[0].v = '1;
            on.crp[0].adr = on.orb[oid].adr;
            on.crp[0].eid = on.orb[oid].eid;
            on.orb[oid].st = dos_asb;
            if(on.orb[oid].at inside {at_rd, at_wr}) begin
              on.crclv = '1;
              on.crStrb = '1;
            end else begin
              on.crclv = '0;
              on.crStrb = en.erib[on.orb[oid].sid].a.strb;
              for(int cl = 0; cl < NUM_DCHE_CL; cl++)
                on.crclv[cl] = on.crStrb[cl] != '0;
            end
          end
          
          if(on.orb[oid].clcwr || on.orb[oid].clrwr) begin
            on.clp[0].v = '1;
            on.clp[0].cwr = on.orb[oid].clcwr;
            on.clp[0].rwr = on.orb[oid].clrwr;
            on.clp[0].adr = on.orb[oid].adr;
            on.clp[0].radr = on.orb[oid].ar.adr;
            on.clp[0].rv = on.orb[oid].ar.v;
            on.clp[0].edib = on.orb[oid].sid;
            on.clp[0].rid = rid;
            on.clp[0].oid = oid;
            on.orb[oid].st = dos_asb;
            on.clclv = '0;
            for(int cl = 0; cl < NUM_DCHE_CL; cl++)
              on.clclv[cl] = en.edib[on.clp[0].edib].d[cl].strb != '0;
          end
        end else if(on.asbv != '1) begin
          on.orb[oid].st = dos_asb;
          on.asbv[asid] = '1;
          on.asb[asid].ar = on.orb[oid].ar;
          on.asb[asid].sid = on.orb[oid].sid;
          on.asb[asid].adr = on.orb[oid].adr;
          on.asb[asid].useAdr = !on.orb[oid].ar.sm;
          on.asb[asid].rw = on.orb[oid].rw;
          on.asb[asid].rid = rid;
        end
      end
        
      on.bkrid[1] = o.bkrid[0];
      on.bkrasid[1] = o.bkrasid[0];
      on.bkraid[1] = o.bkraid[0];
      on.bkv = '0;
      on.bkw = '0;
      on.clp[2] = o.clp[1];
      if(!on.crp[2].v)
        on.crp[2] = o.crp[1];
      if(!on.srp[1].v) begin
        on.srp[1] = o.srp[0];
        on.srp[0].v = '0;
      end else
        on.srp[1].start = '0;
      on.crp[1] = o.crp[0];
      on.clp[1] = o.clp[0];
      
      ///select cache read first
      if(on.crp[0].v && !on.crp[2].v) begin
        on.bkv = '1;
        for(int i = 0; i < NUM_DCHE_CL; i++)
          if(on.crclv[i]) begin
            on.crclv[i] = '0;
            on.crp[0].adr.cl = i;
            on.crp[0].rv = on.crStrb[i];
            break;
          end
        on.dRadr = '{default : on.crp[0].adr};
        on.bkv = '1;
      end
      
      ///select cache load second
      if(on.clp[0].v && (!on.clp[0].v || (on.crp[0].adr != on.clp[0].adr && DP_OCM_BK))) begin
        if(on.clp[0].cwr) begin
          on.dBe = en.edib[on.clp[0].edib].d[on.clp[0].adr.cl].strb;    
          on.dWadr = '{default : on.clp[0].adr};
          on.bkw = '1;
          for(int i = 0; i < NUM_DCHE_CL; i++)
            if(on.clclv[i]) begin
              on.clclv[i] = '0;
              on.clp[0].adr.cl = i;
              break;
            end
        end
        
        if(on.clp[0].rwr) begin
          on.bkrid[0] = '{default : on.clp[0].rid};
          on.clp[0].bp = '1;
          on.bkv = '1;
          for(int j = 0; j < NUM_DCU_ASB; j++)
            for(int bk = 0; bk < NUM_SMEM_BK; bk++)
              if(on.clp[0].rv[j][bk] && on.clp[0].radr[j][bk].cl == on.clp[0].adr.cl)
                on.bkrasid[0][bk] = j;
        end
      end
 
      on.clp[0].v = on.clp[0].adr.cl == '0;
      on.crp[0].v = on.crclv == '0;
      on.clp[0].last = o.clp[0].v && !on.clp[0].v;
      on.crp[0].last = o.crp[0].v && !on.crp[0].v;
      
      ///select request from oa for cache data access third
      for(int bk = 0; bk < NUM_SMEM_BK; bk++) begin
        for(int i = 0; i < NUM_DCU_ASB; i++) begin
          if(!on.asbv[i] || (on.crp[0].v && !on.asb[i].rw))
            continue;
          for(int j = 0; j < NUM_ASB_CYC; j++) begin
            if((on.asb[i].rw && on.bkv[bk])
              || (!on.asb[i].rw && on.bkw[bk])
              || ((on.bkv[bk] || on.bkw[bk]) && DP_OCM_BK)
            )
              continue;
            if(on.asb[i].ar.v[j][bk]) begin
              on.bkv[bk] = on.asb[i].rw;
              on.bkw[bk] = !on.asb[i].rw;           
              if(on.asb[i].rw) begin
                on.bkrid[0][bk] = on.asb[i].rid;
                on.bkrasid[0][bk] = j;
                on.bkraid[0][bk] = i;
                on.dRadr[bk] = on.asb[i].useAdr ? on.asb[i].adr : on.asb[i].ar.adr[j][bk];
              end else begin
                on.bksid[bk] = on.asb[i].sid;
                on.bksasid[bk] = j;
                on.dWadr[bk] = on.asb[i].useAdr ? on.asb[i].adr : on.asb[i].ar.adr[j][bk];
                on.dBe[bk] = on.asb[i].ar.v[i][bk];
              end
              on.asb[i].ar.v[j][bk] = '0;
            end
          end
        end
      end
      
      dWadr = o.dWadr;
      dRadr = o.dRadr;
      dBe = o.dBe;
      rBe = '0;
      rWr = o.bkw;
      rWadr = o.bkrid[1];
      if(!on.srp[1].start) begin
        for(int bk = 0; bk < NUM_SMEM_BK; bk++)
          for(int j = 0; j < NUM_ASB_CYC; j++)
            sRadr[j][bk] = on.bksid[bk];
      end else
        sRadr = '{default : on.srp[1].sid};

      ///write to rdb strb
      for(int bk = 0; bk < NUM_SMEM_BK; bk++) begin
        rBe[o.bkrasid[1][bk]][bk] = rWr[bk];
        on.rstrb[o.bkraid[1][bk]][o.bkrasid[1][bk]][bk] |= rWr[bk];
      end
      
      ///select from asb to finish
      begin
        logic fnd;
        dcasb_t asid;
        dcorb_t oid;
        {fnd, asid, oid} = '0;
        
        for(int i = 0; i < NUM_DCU_ASB; i++) begin
          if(on.asbv[i] && on.asb[i].ar.v == '0) begin
            asid = i;
            fnd = '1;
            break;
          end
        end
        
        ///report to erb
        if(o.crp[2].v && o.crp[2].last && !on.odv) begin
          on.crp[2].v = '0;
          on.odv = '1;
          on.od = io.wbData;
          on.odEid = o.crp[2].eid;
          on.odat = o.crat;
          on.odStrb = io.wbStrb;
///          on.odclv = o.crclv;
        end else if(o.srp[1].v && !on.odv) begin
          on.srp[1].v = '0;
          on.odv = '1;
          on.od = io.stData;
          on.odEid = o.srp[1].eid;
          on.odat = at_wr;
          on.odStrb = io.stStrb;
///          on.odclv = o.srp[1].clv;
        end
        on.odclv = '0;
        for(int cl = 0; cl < NUM_DCHE_CL; cl++)
          for(int bk = 0; bk < NUM_SMEM_BK; bk++)
            on.odclv[cl] |= on.odStrb[cl][bk];
            
        ///report to rrb
        if(o.clp[2].v
          && o.clp[2].rwr
          && o.clp[2].last
        ) begin
          oid = on.clp[2].oid;
          fnd = '1;
        end else if(fnd) begin
          oid = on.asb[asid].oid;
          if(o.orb[oid].st == dos_asb && !sn.oapWr) begin
            on.asbv[asid] = '0;
            sn.oapWr = '1;
            sn.oapRrb.s.id = on.asb[asid].ar.rid;
            sn.oapRrb.s.exp = on.asb[asid].ar.llsc ? '{default : exr_exok} : '{default : exr_ok};
            sn.oapRrb.ls = on.asb[asid].ar.ls;
            sn.oapRrb.rid = on.asb[asid].rid;
            if(sn.oapRrb.ls)
              for(int as = 0; as < NUM_ASB_CYC; as++)
                for(int bk = 0; bk < NUM_SMEM_BK; bk++)
                  if(!on.rstrb[asid][as][bk] && on.orb[oid].ar.v[as][bk] != '0) begin
                    cyc_t cyc;
                    spid_t sp;
                    asbc_t as1;
                    bk_t bk1;
                    as1 = as;
                    bk1 = bk;
                    {cyc, sp} = {as1, bk1};
                    sn.oapRrb.s.exp[cyc][sp] = exr_ecc;
                  end
          end else
            fnd = '0;
        end
                
        if(fnd)
          for(int i = 0; i < NUM_DCU_ORB; i++) begin
            on.orb[i].orbw[oid] = '0;
            if(on.orb[i].orbw == '0 && o.orb[oid].st == dos_dep)
              on.orb[oid].st = dos_rdy;
          end
      end
    end : onchip_access_proc
    
    begin : tlb_proc_part1
      if(!rn.tlbp.v) begin
        ///tlb tag proc
        rn.tlbp = dcu_irp_inf_def;
        if(r.dibrdy != r.dibrp || r.dibrf) begin
          inf.dcu2tlb.req = !r.dib[r.dibrp].ar.sm;
          inf.dcu2tlb.r.vpn = r.dib[r.dibrp].ar.chadr >> WID_NVADR;
          inf.dcu2tlb.r.gid = r.dib[r.dibrp].ar.gid;
          rn.tlbp.v = '1;
          rn.tlbp.ar = r.dib[r.dibrp].ar;
          rn.tlbp.sid = r.dib[r.dibrp].sid;
          rn.dibrp++;
        end else if(r.ribrp != r.ribwp || r.ribf) begin
          inf.dcu2tlb.req = !r.rib[r.ribrp].ar.sm;
          inf.dcu2tlb.r.vpn = r.rib[r.ribrp].ar.chadr >> WID_NVADR;
          inf.dcu2tlb.r.gid = r.rib[r.ribrp].ar.gid;
          rn.tlbp.v = '1;
          rn.tlbp.ar = r.dib[r.dibrp].ar;
          rn.tlbp.d = r.dib[r.dibrp].d;
          rn.ribrp++;
        end
      end
    end : tlb_proc_part1
    
    begin : biu_req
      logic fnd;
      dcerb_t eid;
      
      if((io.biu.rsp.od && io.dcu2biu.req.odlast) || !io.dcu2biu.req.od)
        on.odv = '0;

      on.odlast = '0;
      if(on.odv && io.biu.rsp.od) begin
        for(int i = 0; i < NUM_DCHE_CL; i++)
          if(on.odclv[i]) begin
            on.odcl = i;
            on.odclv[i] = '0;
            break;
          end
        on.odlast = on.odclv == '0;
      end
      
      ///ar req search
      for(int i = 0; i < NUM_DCU_ERB; i++)
        if(en.erbv[i] && en.erb[i].areq) begin
          if(!(en.erb[i].oa.at == at_wr && !en.erb[i].flush && on.srp[1].v)) begin
            fnd = '1;
            eid = i;
            break;
          end
        end
        
      if((!io.dcu2biu.req.ar || io.biu.rsp.ar) && fnd) begin
        en.arReq = '1;
        en.arEid = eid;
        en.erb[eid].areq = '0;
        if(en.erb[eid].oa.at == at_wr && !en.erb[eid].flush) begin
          on.srar = en.erb[eid].ar;
          on.srp[0].sid = en.erb[eid].sid;
          on.srp[0].eid = eid;
          on.srp[0].v = '1;
          on.srp[0].start = '1;
        end
      end
    end : biu_req
    
    begin : orb_update
      logic fnd;
      dcorb_t orbid;
      {fnd, orbid} = '0;
      
      for(int i = 0; i < NUM_DCU_ORB; i++)
        if(on.orb[i].st == dos_i) begin
          fnd = '1;
          orbid = i;
          break;
        end
        
      if((on.irWr || on.erWr) && fnd) begin
        dcu_orb_inf_s orbwd;
        if(on.irWr) begin
          on.irWr = '0;
          orbwd = on.irOrb;
        end else begin
          on.erWr = '0;
          orbwd = on.erOrb;
        end
          
        for(int i = 0; i < NUM_DCU_ORB; i++)
          if(on.orb[i].st != dos_i
            && (on.orb[i].adr.idx == orbwd.adr.idx)
            && (on.orb[i].adr.par == orbwd.adr.par)
            && (on.orb[i].adr.aso == orbwd.adr.aso)
          ) begin
            if(on.orb[i].rw || on.orb[i].cr)
              orbwd.orbw[i] = !orbwd.rw || orbwd.clcwr;
            else if(!on.orb[i].rw || on.orb[i].clcwr)
              orbwd.orbw[i] = orbwd.rw || orbwd.cr;
          end
          
        if(orbwd.sm || orbwd.ar.sm) begin
          orbwd.st = dos_rdy;
          orbwd.orbw = '0;
        end if(orbwd.orbw != '0)
          orbwd.st = dos_dep;
        else
          orbwd.st = dos_rdy;
        
        on.orb[orbid] = orbwd;
      end
    end : orb_update
    
    begin : lsu_rsp
      if(!sn.rrbf) begin
        if(sn.oapWr) begin
          sn.oapWr = '0;
          sn.rrb[sn.rrbwp] = sn.oapRrb;
        end else if(sn.erpWr) begin
          sn.erpWr = '0;
          sn.rrb[sn.rrbwp] = sn.oapRrb;
        end else if(sn.irpWr) begin
          sn.irpWr = '0;
          sn.rrb[sn.rrbwp] = sn.irpRrb;
        end else if(sn.tlbpWr) begin
          sn.tlbpWr = '0;
          sn.rrb[sn.rrbwp] = sn.oapRrb;
        end
        if(sn.oapWr || sn.erpWr || sn.tlbpWr)
          sn.rrbwp++;
      end
      rRadr = sn.rrb[sn.rrbrp].rid;
      if((sn.rrbrp != sn.rrbwp || sn.rrbf) && io.lsu.rsp.ld)
        sn.rrbrp++;
      sn.rrbf = sn.rrbrp == sn.rrbwp && (s.rrbrp == (s.rrbwp + 1'b1) || s.rrbf);
    end : lsu_rsp
  end : comb_logic
  
  always_comb
  begin : iorsp_logic
    ion = io;    
    ion.lsu.req = inf.lsu2dcu.req;
    ion.lsu.rsp = inf.lsu2dcu.rsp;
    ion.biu.req = inf.biu2dcu.req;
    ion.biu.rsp = inf.biu2dcu.rsp;

    rDatai = o.clp[1].bp ? io.bpData : dDatao;
    for(int bk = 0; bk < NUM_SMEM_BK; bk++) begin
      if(o.clp[0].v && o.clp[0].cwr)
        dDatai[bk] = en.edib[o.clp[0].edib].d[o.clp[0].adr.cl].data[bk];
      else
        dDatai[bk] = sDatao[o.bksasid[bk]][bk];
    end
    if(o.clp[0].bp)
      ion.bpData = dDatai;
      
    if(inf.dcu2tlb.req)
      ion.tlb = inf.tlb2dcu;
      
    if(cn.irRd) begin
      ion.irTag = tDatao[0];
      if(cn.erWr && cn.irRdIdx == cn.erWrIdx)
        ion.irTag[cn.erWrAso] = cn.erWrTag;
    end
    
    if(cn.erRd) begin
      ion.erTag = tDatao[1];
      if(cn.erWr && cn.irRdIdx == cn.erWrIdx)
        ion.erTag[cn.erWrAso] = cn.erWrTag;
    end
    
    sDatai = inf.lsu2dcu.sd.data;
    
    if(inf.lsu2dcu.ar.ls)
      ion.dcu2lsu.rsp.a = !rn.ribf;
    else
      ion.dcu2lsu.rsp.a = '1;

    if(ion.dcu2lsu.rsp.sd && inf.lsu2dcu.req.sd) begin
      ion.lsu.sd = inf.lsu2dcu.sd;
    end else if(ion.dcu2lsu.rsp.sd)
      ion.lsu.sd.dv = '0;
    
    if(inf.lsu2dcu.rsp.ld)
      ion.dcu2lsu.req.ld = '0;
      
    if((sn.rrbrp != sn.rrbwp || sn.rrbf) && !sn.rrb[sn.rrbrp].ls && !ion.dcu2lsu.req.ld) begin
      ion.dcu2lsu.req.ld = '1;
      ion.dcu2lsu.ld.exp = sn.rrb[sn.rrbrp].s.exp;
      ion.dcu2lsu.ld.id = sn.rrb[sn.rrbrp].s.id;
    end
    
    if(io.dcu2lsu.req.ld && io.lsu.rsp.ld)
      ion.dcu2lsu.ld.data = rDatao;
    
    if(inf.lsu2dcu.rsp.s)
      ion.dcu2lsu.req.s = '0;
    
    if((sn.rrbrp != sn.rrbwp || sn.rrbf) && sn.rrb[sn.rrbrp].ls && !ion.dcu2lsu.req.s) begin
      ion.dcu2lsu.req.s = '1;
      ion.dcu2lsu.s = sn.rrb[sn.rrbrp].s;
    end
        
    ion.dcu2biu.rsp.id = !rn.dibf;
    if(ion.dcu2biu.rsp.id && inf.biu2dcu.req.id)
      ion.biu.id = inf.biu2dcu.id;
    
    if(inf.biu2dcu.rsp.ar)
      ion.dcu2biu.req.ar = '0;
    
    if(!ion.dcu2biu.req.ar && en.arReq) begin
      ion.dcu2biu.req.ar = '1;
      ion.dcu2biu.ar = en.erb[en.arEid].oa;
    end
      
    if(!ion.dcu2biu.req.od && on.odv) begin
      ion.dcu2biu.req.od = '1;
      ion.dcu2biu.req.odlast = on.odlast;
      ion.dcu2biu.req.odcl = on.odcl;
      ion.dcu2biu.od.strb = on.odStrb;
      ion.dcu2biu.od.data = on.od[on.odcl];
    end
    
    if(o.srp[1].start) begin
      ion.stStrb = '0;
      for(int cl = 0; cl < NUM_DCHE_CL; cl++)
        for(int bk = 0; bk < NUM_SMEM_BK; bk++)
          for(int as = 0; as < NUM_ASB_CYC; as++)
            if(o.srar.adr[as][bk].cl == cl && o.srar.v[as][bk] != '0) begin
              ion.stData[cl][bk] = sDatao[as][bk];
              ion.stStrb[cl][bk] = o.srar.v[as][bk];
            end
    end
      
    if(inf.biu2dcu.rsp.od)
      ion.dcu2biu.req.od = '0;
      
    if(o.crp[1].v) begin
      ion.wbData[o.crp[1].adr.cl] = dDatao;
      ion.wbStrb[o.crp[1].adr.cl] = o.crp[1].rv;
    end
    
    if(inf.biu2dcu.rsp.ir)
      ion.dcu2biu.req.ir = '0;
    
    if(!ion.dcu2biu.req.ir && e.erp[2].v && !e.erp[2].iaWait) begin
      ion.dcu2biu.req.ir = '1;
      ion.dcu2biu.ir = e.erp[2].ir;
    end
    
    ion.dcu2biu.rsp.ia = inf.biu2dcu.ia.hasData ? '1 : !en.eribf;
    ion.dcu2biu.rsp.id = !en.edibf; 
    inf.dcu2biu = ion.dcu2biu;
    inf.dcu2lsu = ion.dcu2lsu;
    ion.dcu2tlb = inf.dcu2tlb;          
  end : iorsp_logic
  
  xpip_ram #(
    .word_width ($bits(tag_t) * NUM_DCHE_ASO),
    .addr_width (WID_DCHE_IDX),
    .num_words  (NUM_DCHE_ENT),
    .bc_width   ($bits(tag_t)),
    .two_port   (1),
    .bp         (1)
  )tagram0(
    .clk,
    .wr     (tWr),
    .be     (tBe),
    .datai  (tDatai),
    .datao  (tDatao[0]),
    .radr   (tRadr[0]),
    .wadr   (tWadr),
    .datao_d()
  );

  xpip_ram #(
    .word_width ($bits(tag_t) * NUM_DCHE_ASO),
    .addr_width (WID_DCHE_IDX),
    .num_words  (NUM_DCHE_ENT),
    .bc_width   ($bits(tag_t)),
    .two_port   (1),
    .bp         (0)
  )tagram1(
    .clk,
    .wr     (tWr),
    .be     (tBe),
    .datai  (tDatai),
    .datao  (tDatao[1]),
    .radr   (tRadr[1]),
    .wadr   (tWadr),
    .datao_d()
  );
  
genvar i, j;  
for(i = 0; i < NUM_SMEM_BK; i++) begin : dbk
  xpip_ram #(
    .word_width ($bits(byt) * WORD_BYTES),
    .addr_width (WID_DCHE_IDX + WID_DCHE_CL + WID_SMEM_PAR + WID_DCHE_ASO),
    .num_words  (NUM_DCHE_ENT * NUM_DCHE_CL * NUM_SMEM_PAR * NUM_DCHE_ASO),
    .bc_width   ($bits(byt)),
    .two_port   (DP_OCM_BK),
    .bp         (0)
  )dataram(
    .clk,
    .wr     (dWr[i]),
    .be     (dBe[i]),
    .datai  (dDatai[i]),
    .datao  (dDatao[i]),
    .radr   (dRadr[i]),
    .wadr   (dWadr[i]),
    .datao_d()
  );

  for(j = 0; j < NUM_ASB_CYC; j++) begin : cyc
    xpip_ram #(
      .word_width ($bits(word)),
      .addr_width (WID_DCU_SDB),
      .num_words  (NUM_DCU_SDB),
      .bc_width   ($bits(word)),
      .two_port   (1),
      .bp         (1)
    )storeram(
      .clk,
      .wr     (sWr),
      .be     ('1),
      .datai  (sDatai[j][i]),
      .datao  (sDatao[j][i]),
      .radr   (sRadr[j][i]),
      .wadr   (sWadr),
      .datao_d()
    );
  
    xpip_ram #(
      .word_width ($bits(word)),
      .addr_width (WID_DCU_RDB),
      .num_words  (NUM_DCU_RDB),
      .bc_width   ($bits(word)),
      .two_port   (1),
      .bp         (1)
    )resram(
      .clk,
      .wr     (rWr[i]),
      .be     (rBe[j][i]),
      .datai  (rDatai[i]),
      .datao  (rDatao[j][i]),
      .radr   (rRadr),
      .wadr   (rWadr[i]),
      .datao_d()
    );
  end : cyc
end : dbk

endmodule